import dayjs from "dayjs";
import { getUnixTimeAndZone, timestamp2Arr, isValidZeroOrOne, toHexString } from "../../utils/utils.js";
import { CommandQueue } from "../CommandQueue.js";

// service : 0x0001
// write : 0x0010
// read notify: 0x0011
/**
 * 目录格式
 * 格式： frame_type + frame_id + cmd + subCmd + Data
 * 解释： frame_type：1字节，0代表该命令为单独命令，只有这一帧； 1和2表示该命令为连续帧，1代表第一帧，2代表后续帧； 3目前用不到
 *        frame_id：请求的时候为随机1个字节 可以和响应的frame_id对应上
 *          cmd: 主命令 1字节
 *          subCmd：子命令 1字节
 *          Data：数据 N字节
 */

/**
 * 设置时间(0x00) 时间同步(0x10)
 *  00(ft) 3f(fi,随机值) 10(cmd) 00(subCmd) 87 a3 6f 0f 09 8b 01 00 00(时间) 08(时区)
 *
 * 注：1、帧结构中的多字节数据采用小端模式存储，低字节在前，高字节在后。
 *
 * 48 b2 6f 0f 09 8b 01
 * 01 8b 09 0f 6f b2 48
 *
 * 018b096fb248  => 1696670397000   Sat Oct 07 2023 17:19:57 GMT+0800 (中国标准时间)
 *
 * 018b090fb248  => 1696664105544   Sat Oct 07 2023 15:35:05 GMT+0800 (中国标准时间)
 *
 * 018b090f6f48  => 1696664088392   Sat Oct 07 2023 15:34:48 GMT+0800 (中国标准时间)
 *
 * 018b090f6fb2  => 1696664088498   Sat Oct 07 2023 15:34:48 GMT+0800 (中国标准时间)
 *
 * @returns 协议头(1 + 1) + 指令(1 + 1) + 时间戳转16进制字符串的小端(8个字节) + 时区(1个字节， 东西区的格式未给)
 */
const setTime = () => {
	const header = [0x00, 0x10, 0x10, 0x00]; // 1.协议头 单帧；2.帧ID 随机，但是我定为指令值；3.cmd；4.subCmd
	const { decimalArr } = getUnixTimeAndZone();
	return CommandQueue.enqueue([...header, ...decimalArr, 0x08]);
};

/**
 * 获取时间(0x01) 时间同步(0x10)
 *
 * 注：1、帧结构中的多字节数据采用小端模式存储，低字节在前，高字节在后。
 *
 * 时间解析与「设置时间」的时间戳反向一致
 * @returns 协议头(1 + 1) + 指令(1 + 1) + 时间戳转16进制字符串的小端(8个字节) + 时区(1个字节， 东西区的格式未给)
 */
const getTime = () => {
	const header = [0x00, 0x10, 0x10, 0x01];
	return CommandQueue.enqueue([...header]);
};

/**
 * 软件版本号(0x00) 版本号读取(0x11)
 * 00 01(协议头) 11 00(指令头) 32 2e 33 2e 38 2e 39 31 20 20 =16转10> 50 46 51 46 56 46 57 49 32 32 =10转ASCII> 2.3.8.91
 *
 * @returns
 */
const getSoftVersion = () => {
	const header = [0x00, 0x11, 0x11, 0x00];
	return CommandQueue.enqueue([...header]);
};

/**
 * 硬件版本号(0x01) 版本号读取(0x11)
 * 00 01(协议头) 11 01(指令头) 36 30 33 53 56 32 2e 30 2e 32 =16转10> 54, 48, 51, 83, 86, 50, 46, 48, 46, 50 =10转ASCII> 603SV2.0.2
 *
 * @returns
 */
const getHardVersion = () => {
	const header = [0x00, 0x11, 0x11, 0x01];
	return CommandQueue.enqueue([...header]);
};

/**
 * 电池电量(0x00) 电池管理(0x12)
 * 00 05(协议头) 12 00(指令头) 58 =16转10> 0-100为正常电量xx% 101为充电中 102为充电完成=>100%
 * @returns
 */
const getBatteryLevel = () => {
	const header = [0x00, 0x12, 0x12, 0x00];
	return CommandQueue.enqueue([...header]);
};

/**
 * 充电状态(0x01) 电池管理(0x12)
 * 00 05(协议头) 12 01(指令头) 00 =16转10> 0为未充电  1为充电中  2为充电完成
 * @returns
 */
const getBatteryCharing = () => {
	const header = [0x00, 0x12, 0x12, 0x01];
	return CommandQueue.enqueue([...header]);
};

/**
 * 电量应答(0x02) 电池管理(0x12)
 * 收到的推送帧：：00 07(协议头) 12 02(指令头) 0A =16转10> 10% 可以回应
 * @returns
 */
const answerBatteryCall = () => {
	const header = [0x00, 0x12, 0x12, 0x02];
	return CommandQueue.enqueue([...header]);
};

/**
 * 主动测量(0x00) 实时心率和心率变异性测量（0x31）
 *
 * @param {Number} detection 1个字节 测量时间 秒
 * @param {Number} frequency 1个字节 测量频率 hz
 * @param {Number} progress  1个字节  进度上报  0 和 1
 * @param {Number*} waveform 1个字节波形上报  0 和 1
 * @param {Number} period    1个字节期间上报  0 和 1
 *
 *
 * 响应结果
 * 00 09(协议头) 31 00(指令头) 03(佩戴和采集状态) 3b(心率) 00(hrv ms) 00(压力) bc 0d(温度， 0.01℃) => 0d bc =16转10> 3516 * 0.01 => 35.16℃
 * @returns
 */
const testHeartRateHrv = (detection = 30, frequency = 25, progress = 1, waveform = 0, period = 0) => {
	if (
		typeof detection !== "number" ||
		typeof frequency !== "number" ||
		typeof progress !== "number" ||
		typeof waveform !== "number" ||
		typeof period !== "number"
	) {
		throw new Error("参数类型错误");
	}

	if (detection === 0) {
		throw new Error("测量时间不能为0");
	}

	if (frequency === 0) {
		throw new Error("测量频率不能为0");
	}

	if (!isValidZeroOrOne(progress) || !isValidZeroOrOne(waveform) || !isValidZeroOrOne(period)) {
		throw new Error("参数值错误");
	}

	const header = [0x00, 0x31, 0x31, 0x00];
	return CommandQueue.enqueue([...header, detection, frequency, waveform, progress, period]);
};

const stopTestHeartRateHrv = () => {
	return CommandQueue.enqueue([0x00, 0x31, 0x31, 0x04]);
};

/**
 * 回应心率推送(0x03)  实时心率和心率变异性测量（0x31）
 * @returns
 */
const answerHeartRateHrv = () => {
	const header = [0x00, 0x31, 0x31, 0x03];
	return CommandQueue.enqueue([...header]);
};

/**
 * 主动测量(0x00)  实时血氧和心率测量（0x32）
 *
 * @param {Number} detection 1个字节 测量时间 秒
 * @param {Number} frequency 1个字节 测量频率 hz
 * @param {Number} progress  1个字节  进度上报  0 和 1
 * @param {Number*} waveform 1个字节波形上报  0 和 1
 *
 * 响应结果
 * 00 0b(协议头) 32 00(指令头) 03(佩戴和采集状态) 00(心率) 00(血氧) 58 0d(温度， 0.01℃) => 0d 58 =16转10> 3416 * 0.01 => 34.16℃
 *
 * @returns
 */
const testBloodOxygen = (detection = 30, frequency = 25, progress = 1, waveform = 0) => {
	if (typeof detection !== "number" || typeof frequency !== "number" || typeof progress !== "number" || typeof waveform !== "number") {
		throw new Error("参数类型错误");
	}

	if (detection === 0) {
		throw new Error("测量时间不能为0");
	}

	if (frequency === 0) {
		throw new Error("测量频率不能为0");
	}

	if (!isValidZeroOrOne(progress) || !isValidZeroOrOne(waveform)) {
		throw new Error("参数值错误");
	}

	const header = [0x00, 0x32, 0x32, 0x00];
	return CommandQueue.enqueue([...header, detection, frequency, waveform, progress]);
};

const stopTestBloodOxygen = () => {
	const header = [0x00, 0x32, 0x32, 0x06];
	return CommandQueue.enqueue([...header]);
};

/**
 * 回应血氧推送(0x03)  实时心率和心率变异性测量（0x32）
 * @returns
 */
const answerBloodOxygen = () => {
	const header = [0x00, 0x32, 0x32, 0x03];
	return CommandQueue.enqueue([...header]);
};

/**
 * 温度测量（0x34）
 * 示例数据：
 * 00 0d 34 00 01(测量状态) 6f 0d =16转10> 3439 * 0.01 => 34.39℃
 * @returns
 */
const testTemperature = () => {
	const header = [0x00, 0x34, 0x34, 0x00, 0x00];
	return CommandQueue.enqueue([...header]);
};

/**
 * 读取当天实时步数(0x00) 计步（0x35）
 * 示例数据：00 0f(同上) 35 00(同上) 33 03 =反转 16转10> 819
 * @returns
 */
const getRealTimeStep = () => {
	const header = [0x00, 0x35, 0x35, 0x00];
	return CommandQueue.enqueue([...header]);
};

const clearRealTimeStep = () => {
	const header = [0x00, 0x35, 0x35, 0x01];
	return CommandQueue.enqueue([...header]);
};

/**
 * 读取本地数据的「未上传」的历史记录(0x00)
 * 读取本地数据的「所有」的历史记录(0x01)
 * 操作本地数据（0x36）
 *
 * @param {Boolean} all 是否获取全部历史数据；默认false； false只获取未提交过的数据； true是获取全部数据
 * @param {Number} fetchUnix 时间戳 可以为0； 为0时，获取缓存内全部未上传数据； 非0时，为 UNIX 时间；
 *
 * 00 13(协议头)  36 00(指令头)            4个
 * 24 00 00 00 翻转 00 00 00 24  (总数)   4个
 * 01 00 00 00 翻转 00 00 00 01  (序号)   4个
 * c7 e9 21 65 翻转 65 21 e9 c7  (时间)   4个
 * 59 00 翻转 00 59 (步数) 2个
 * 00 心率
 * 00 血氧
 * 00 hrv
 * 00 压力
 * 00 00 温度
 * 00 运动
 * 01 睡眠类型
 * 01 血液灌注率
 * 00 保留
 * 00 保留
 * 00 RR长度N 最大100
 *  N * (ij xy)
 * @returns
 */
const getHistoryData = (all = false, fetchUnix = 0) => {
	if (typeof all !== "boolean" || typeof fetchUnix !== "number") {
		throw new Error("参数类型错误");
	}
	const type = all ? 0x01 : 0x00;
	const header = [0x00, 0x36, 0x36, type];
	const data = [];
	if (fetchUnix === 0) {
		data.push(0x00, 0x00, 0x00, 0x00);
	} else {
		const { decimalArr } = timestamp2Arr(fetchUnix);
		data.push(...decimalArr);
	}
	return CommandQueue.enqueue([...header, ...data]);
};

/**
 * 停止上传本地数据(0x02)
 * 操作本地数据（0x36）
 * @returns
 */
const stopGetHistoryData = () => {
	const header = [0x00, 0x36, 0x36, 0x02];
	return CommandQueue.enqueue([...header]);
};

/**
 * 删除全部本地数据历史记录(0x03)
 * 操作本地数据（0x36）
 * @returns
 */
const clearHistoryData = () => {
	const header = [0x00, 0x36, 0x36, 0x03];
	return CommandQueue.enqueue([...header]);
};

/**
 * 读取本地数据内存容量信息(0x04)
 * 操作本地数据（0x36）
 *
 * 示例数据：
 * 0021 3604
 * 08 f6 01 00 硬盘大小 =翻转 16转10> 00 01 f6 08 => 128520 =转M> 128520 / 1024 / 1024
 * e0 4c 00 00 已使用 =翻转 16转10> 00 00 4c e0 => 19680 =转M> 19680 / 1024 / 1024
 * 7f 02 全部记录数 =翻转 16转10> 02 7f => 639
 * 0b 00 未上传记录  =翻转 16转10> 00 0b => 11
 * @returns
 */
const getHistoryMemorySize = () => {
	const header = [0x00, 0x36, 0x36, 0x04];
	return CommandQueue.enqueue([...header]);
};

/**
 * 采集周期设置(0x00) 系统设置（0x37）
 * @param {*} period 采集周期 单位秒。为0时关闭周期采集，正常值为最小60s
 * @returns
 */
const setPeriod = (period = 20 * 60) => {
	const header = [0x00, 0x37, 0x37, 0x00];
	const hex = toHexString(period);
	return CommandQueue.enqueue([
		...header,
		...hex
			.match(/.{1,2}/g)
			.reverse()
			.map((hex) => parseInt(hex, 16)),
	]);
};

/**
 * 采集周期读取(0x01) 系统设置（0x37）
 * @param {*} period 采集周期 单位秒。为0时关闭周期采集，正常值为最小60s
 *
 * 示例数据：0019 3701 b0 04 00 00，1200 秒
 * b0 04 00 =翻转 16转10> 00 04 b0 => 1200 秒
 * @returns
 */
const getPeriod = () => {
	const header = [0x00, 0x37, 0x37, 0x01];
	return CommandQueue.enqueue([...header]);
};

/**
 * 恢复出厂设置(0x02) 系统设置（0x37）
 * @returns
 */
const factoryReset = () => {
	const header = [0x00, 0x37, 0x37, 0x02];
	return CommandQueue.enqueue([...header]);
};

export const protocol = {
	setTime,
	getTime,
	getSoftVersion,
	getHardVersion,
	getBatteryLevel,
	getBatteryCharing,
	answerBatteryCall,
	testHeartRateHrv,
	stopTestHeartRateHrv,
	answerHeartRateHrv,
	testBloodOxygen,
	stopTestBloodOxygen,
	answerBloodOxygen,
	testTemperature,
	getRealTimeStep,
	clearRealTimeStep,
	getHistoryData,
	stopGetHistoryData,
	clearHistoryData,
	getHistoryMemorySize,
	setPeriod,
	getPeriod,
	factoryReset,
};

// 接收解析

const getResponseHeader = (hex) => {
	if (typeof hex !== "string") throw new Error("参数类型错误");
	const hexArr = hex.match(/.{1,2}/g);
	if (hexArr.length < 4) throw new Error("数据格式错误");

	const id = parseInt(hexArr[1], 16);
	const cmd = parseInt(hexArr[2], 16);
	const sub = parseInt(hexArr[3], 16);
	const data = hexArr.slice(4);

	return {
		id,
		cmd,
		sub,
		hexArr,
		data,
	};
};

/**
 * 通用设置指令的响应解析
 * @param {String} hex
 */
const commonSettingResponseAnalysis = (hex) => {
	return getResponseHeader(hex);
};

/**
 *
 * @param {*} hex
 * @returns
 */
const commonPushResponseAnalysis = (hex) => {
	const { id, cmd, sub, hexArr } = getResponseHeader(hex);

	const d_c = parseInt(hexArr[2], 16);
	const d_s = parseInt(hexArr[3], 16);

	const defaultData = {
		id,
		cmd,
		sub,
		needAnswer: false,
	};
	let result = {};

	const data = hexArr.slice(4);

	if (d_c === 0x12 && d_s === 0x02) {
		/**
		 * 电量推送
		 * 当电量为 20%，10%，5%的时候，蓝牙连接中，戒指主动进行低电量推送，每个挡位只推送一次。推送完成后 2 秒内等待应答，如果超时或者未收到推送应答，则重复推送，最多三次。
		 */

		const batteryLevel = parseInt(data[0], 16);

		result = {
			batteryLevel,
			needAnswer: true,
		};
	} else if (d_c === 0x31 && d_s === 0x03) {
		/**
		 * 心率推送。
		 * 当心率和心率变异性周期测量的时候，蓝牙连接中，戒指主动进行测量结果推送，每次测量只推一次。推送完成后 2 秒内等待应答，如果超时或者未收到推送应答，则重复推送，最多三次。
		 */
		const heartRate = parseInt(data[0], 16);
		const hrv = parseInt(data[1], 16);
		const press = parseInt(data[2], 16);
		const temperature = parseInt(`${data[4]}${data[3]}`, 16) * 0.01;

		result = {
			heartRate,
			hrv,
			press,
			temperature,
			needAnswer: true,
		};
	} else if (d_c === 0x32 && d_s === 0x03) {
		/**
		 * 血氧推送
		 * 当血氧和心率周期测量的时候，蓝牙连接中，戒指主动进行测量结果推送，每次测量只推一次。推送完成后 2 秒内等待应答，如果超时或者未收到推送应答，则重复推送，最多三次。
		 */

		const heartRate = parseInt(data[0], 16);
		const bloodOxygen = parseInt(data[1], 16);
		const temperature = parseInt(`${data[3]}${data[2]}`, 16) * 0.01;

		result = {
			heartRate,
			bloodOxygen,
			temperature,
			needAnswer: true,
		};
	} else if (d_c === 0x36 && d_s === 0xff) {
		/**
		 * 消极响应
		 * 在获取历史记录或者执行其他指令记录记录时候，如果被测设备不能执行指令，则回复此指令。
		 */
		const reason = parseInt(data[1], 16);
		result = {
			reason,
			description: ["正在测量中", "正在上传历史记录", "正在删除历史记录", "文件系统损坏"][reason],
			needAnswer: false,
		};
	}
	return Object.assign(defaultData, result);
};

/**
 * 实现对戒指的时间读取。
 * @param {*} hex
 * 示例数据：0041100148b26f098b01000008，时间为 2023.10.07.17:19:57.195
 * @returns
 */
const timeGettingAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);

	if (sub === 0x00) {
		return {
			id,
			cmd,
			sub,
		};
	}

	const timestamp = parseInt(data.slice(0, 8).reverse().join(""), 16);
	const timeZone = parseInt(data[8], 16);

	return {
		id,
		cmd,
		sub,
		timestamp,
		timeZone,
		date: dayjs(timestamp).format("YYYY.MM.DD.HH:mm:ss.SSS"),
	};
};

/**
 * 读取软件版本号。0x11 0x00
 * @param {*} hex
 * @returns
 */
const softVersionAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	const softwareVersion = data
		.map((hex) => parseInt(hex, 16))
		.filter((num) => num !== 32)
		.map((num) => String.fromCharCode(num))
		.filter((str) => !!str)
		.join("");

	return {
		id,
		cmd,
		sub,
		softwareVersion,
	};
};

/**
 * 读取硬件版本号。0x11 0x01
 * @param {*} hex
 * @returns
 */
const hardVersionAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	const hardwareVersion = data
		.map((hex) => parseInt(hex, 16))
		.filter((num) => num !== 32)
		.map((num) => String.fromCharCode(num))
		.filter((str) => !!str)
		.join("");

	return {
		id,
		cmd,
		sub,
		hardwareVersion,
	};
};

const wareVersionAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	let softwareVersion, hardwareVersion;
	if (sub === 0x00) {
		softwareVersion = data
			.map((hex) => parseInt(hex, 16))
			.filter((num) => num !== 32)
			.map((num) => String.fromCharCode(num))
			.filter((str) => !!str)
			.join("");
	} else if (sub === 0x01) {
		hardwareVersion = data
			.map((hex) => parseInt(hex, 16))
			.filter((num) => num !== 32)
			.map((num) => String.fromCharCode(num))
			.filter((str) => !!str)
			.join("");
	}

	return {
		id,
		cmd,
		sub,
		softwareVersion,
		hardwareVersion,
	};
};

/**
 * 读取电池电量
 * @param {*} hex
 * 0~100%百分比101 为充电中，电量无效102 为充电完成，电量无效
 * batteryCharging false为「未充电」和 「充电完成」 此时的batteryLevel为具体指或者100； true就是充电中 batteryLevel值无效
 *
 * @returns
 */
const batteryLevelAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	let batteryLevel = parseInt(data[0], 16);

	let result = {
		id,
		cmd,
		sub,
	};

	if (sub === 0x00) {
		if (batteryLevel === 101) {
			result.batteryCharging = true;
			result.batteryLevel = 100;
		} else if (batteryLevel === 102) {
			result.batteryCharging = false;
			result.batteryLevel = 100;
		} else {
			result.batteryCharging = false;
			result.batteryLevel = batteryLevel;
		}
	} else if (sub === 0x01) {
		if (batteryLevel === 1) {
			result.batteryCharging = true;
			result.batteryLevel = -1;
		} else {
			result.batteryCharging = false;
		}
	} else if (sub === 0x02) {
		result.batteryLevel = batteryLevel;
	}

	console.log("🔋 =》 result 《= 🔋", result);

	return {
		...result,
	};
};

const wearMap = {
	0: "未佩戴",
	1: "已佩戴",
	2: "充电中不允许采集",
	3: "采集中",
	4: "戒指繁忙，请稍后",
};

/**
 * 主动测量（0x31 0x00)
 * @param {*} hex
 * @returns
 */
const testHeartRateHrvAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	if (sub === 0xff) {
		// 检测进度
		return {
			id,
			cmd,
			sub,
			wearDescription: "采集中",
			progress: parseInt(data[0], 16),
			finish: false,
		};
	} else if (sub === 0x00) {
		const wear = parseInt(data[0], 16);
		const heartRate = parseInt(data[1], 16);
		const hrv = parseInt(data[2], 16);
		const press = parseInt(data[3], 16);
		const temperature = parseInt(`${data[5]}${data[4]}`, 16) * 0.01;
		const wearDescription = wearMap[wear];

		const result = {
			id,
			cmd,
			sub,
			wear,
			wearDescription,
			heartRate,
			hrv,
			press,
			temperature,
			finish: false,
		};

		if ([0, 2, 4].includes(wear)) {
			progress = 100;
		}

		return {
			...result,
		};
	} else if (sub === 0x04) {
		return {
			id,
			cmd,
			sub,
			finish: true,
		};
	}
};

/**
 * 主动测量 0x32
 * @param {*} hex
 * @returns
 */
const testBloodOxygenAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	if (sub === 0xff) {
		// 检测进度
		return {
			id,
			cmd,
			sub,
			wearDescription: "采集中",
			progress: parseInt(data[0], 16),
			finish: false,
		};
	} else if (sub === 0x00) {
		const wear = parseInt(data[0], 16);
		const heartRate = parseInt(data[1], 16);
		const bloodOxygen = parseInt(data[2], 16);
		const temperature = parseInt(`${data[4]}${data[3]}`, 16) * 0.01;

		const result = {
			id,
			cmd,
			sub,
			wear,
			wearDescription: wearMap[wear],
			heartRate,
			bloodOxygen,
			temperature,
			finish: false,
		};

		if ([0, 2, 4].includes(wear)) {
			progress = 100;
		}

		return {
			...result,
		};
	} else if (sub === 0x06) {
		return {
			id,
			cmd,
			sub,
			finish: true,
		};
	}
};

/**
 * 温度测量（0x34）
 * @param {*} hex
 * @returns
 */
const testTemperatureAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	const wear = parseInt(data[0], 16);
	const temperature = parseInt(`${data[2]}${data[1]}`, 16) * 0.01;
	return {
		id,
		cmd,
		sub,
		wear,
		wearDescription: wearMap[wear],
		temperature,
	};
};

/**
 * 读取当天实时步数（0x35）0x00
 * @param {*} hex
 *
 */
const realTimeStepAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	const step = parseInt(`0x${data[1]}${data[0]}`, 16);

	return {
		id,
		cmd,
		sub,
		step,
	};
};

/**
 * 操作本地数据（0x36）
 * 读取本地数据的未上传的历史记录0x00 以及 读取本地数据的全部的历史记录0x01
 * @param {*} hex
 * 24 00 00 00 翻转 00 00 00 24  (总数)   4个
 * 01 00 00 00 翻转 00 00 00 01  (序号)   4个
 * c7 e9 21 65 翻转 65 21 e9 c7  (时间)   4个
 * 59 00 翻转 00 59 (步数) 2个
 * 00 心率
 * 00 血氧
 * 00 hrv
 * 00 压力
 * 00 00 温度
 * 00 运动
 * 01 睡眠类型
 * 01 血液灌注率
 * 00 保留
 * 00 保留
 * 00 RR长度N 最大100
 *  N * (ij xy)
 */
const historyDataAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);

	const total = parseInt(data.slice(0, 4).reverse().join(""), 16); // 帧总数
	const index = parseInt(data.slice(4, 8).reverse().join(""), 16); // 当前帧序号
	const finish = total === index; // 是否最后一帧

	const timestamp = parseInt(data.slice(8, 12).reverse().join(""), 16);
	const date = dayjs(timestamp * 1000).format("YYYY-MM-DD HH:mm:ss");
	const stepCount = parseInt(data.slice(12, 14).reverse().join(""), 16);
	const heartRate = parseInt(data[14], 16);
	const bloodOxygen = parseInt(data[15], 16);
	const hrv = parseInt(data[16], 16);
	const press = parseInt(data[17], 16);
	const temperature = parseInt(`${data[19]}${data[18]}`, 16) * 0.01;
	const exerciseIntensity = parseInt(data[20], 16);
	const sleepType = parseInt(data[21], 16);
	const bloodPerRate = parseInt(data[22], 16);
	const reserve1 = parseInt(data[23], 16);
	const RRCount = parseInt(data[24], 16);
	const RRList = data.slice(25, 25 + RRCount * 2).reverse().join(' ')

	/**
	 * 00 36 36 01 头
	 * 28 00 00 00 总
	 * 20 00 00 00 当
	 * 71 ff 33 68 时间
	 * 00 00 步
	 * 00 心率
	 * 00 血氧
	 * 00 hrv
	 * 00 压力
	 * 00 00 温度
	 * 02 运动
	 * 01 睡眠
	 * 01 灌注
	 * 63 保留
	 * 04 RR数
	 * 0300 1e03 0000 0a01 => 010a 0000 031e 0003; 300 7683 0 2561 => 266 0 798 3
	 */

	return {
		id,
		cmd,
		sub,
		total,
		index,
		finish,
		timestamp,
		date,
		stepCount,
		heartRate,
		bloodOxygen,
		hrv,
		press,
		temperature: temperature === 0 ? 0 : Number(temperature.toFixed(1)),
		exerciseIntensity,
		sleepType,
		bloodPerRate,
		reserve1,
		RRCount,
		RRList,
	};
};

/**
 * 读取本地数据内存容量信息 0x36 0x04
 * @param {*} hex
 * 08 f6 01 00 硬盘大小 =翻转 16转10> 00 01 f6 08 => 128520 =转M> 128520 / 1024 / 1024
 * e0 4c 00 00 已使用 =翻转 16转10> 00 00 4c e0 => 19680 =转M> 19680 / 1024 / 1024
 * 7f 02 全部记录数 =翻转 16转10> 02 7f => 639
 * 0b 00 未上传记录  =翻转 16转10> 00 0b => 11
 */
const historyMemorySizeAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	const total = parseInt(data.slice(0, 4).reverse().join(""), 16); // 总容量
	const used = parseInt(data.slice(4, 8).reverse().join(""), 16); // 已使用
	const all = parseInt(data.slice(8, 12).reverse().join(""), 16); // 记录数量
	const unUpload = parseInt(data.slice(12, 16).reverse().join(""), 16); // 未提交数量

	return {
		id,
		cmd,
		sub,
		total,
		used,
		all,
		unUpload,
	};
};

const historyDataOrMemory = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	if (sub === 0x00 || sub === 0x01) {
		// 未上传的历史记录
		return historyDataAnalysis(hex);
	} else if (sub === 0x04) {
		// 本地数据内存容量信息
		return historyMemorySizeAnalysis(hex);
	} else if (sub === 0x03) {
		return {
			id,
			cmd,
			sub,
		};
	}
	return null;
};

/**
 *  系统设置（0x37）
 * 采集周期读取。0x1
 * @param {*} hex
 * @returns
 */
const periodAnalysis = (hex) => {
	const { id, cmd, sub, data } = getResponseHeader(hex);
	if (sub === 0x02) {
		return {
			id,
			cmd,
			sub,
			reest: true,
		};
	}
	const period = parseInt(data.reverse().join(""), 16);
	return {
		id,
		cmd,
		sub,
		period,
	};
};

export const response = {
	commonSettingResponseAnalysis,
	commonPushResponseAnalysis,
	timeGettingAnalysis,
	softVersionAnalysis,
	hardVersionAnalysis,
	wareVersionAnalysis,
	batteryLevelAnalysis,
	testHeartRateHrvAnalysis,
	testBloodOxygenAnalysis,
	testTemperatureAnalysis,
	realTimeStepAnalysis,
	historyDataAnalysis,
	historyMemorySizeAnalysis,
	historyDataOrMemory,
	periodAnalysis,
};

// 固件升级  16-bit [GATT Service: 0xff01] [Write: 0xff02] [Notify: 0xff03] [Write no response: 0xff04]

/**
 * 转换BOOT 模式
 * 第一步，连接戒指后，向 OTA 服务 FF02 特征值写入[0x01,0x02]两个字节，由APP 模式切换为BOOT模式，戒指主动断开蓝牙连接。
 * 在 BOOT 模式下，蓝牙广播名称为 PPLUSOTA，MAC 地址为APP模式下的的 MAC 地址加 1。
 * 蓝牙主机需再次连接 BOOT 模式下的从机，MTU 设置为240 字节长度。
 */
const intoBoot = () => {};

/**
 * 发送分区数量
 * 第二步，解析 HEX16 文件，读取分区数量，通过命令通道发送[0x01,n,0x00]给蓝牙从机，
 * n的获取方式为 HEX16 文件中以“:02”为行开头的数量（这个数量我们称为分区数量）。
 * 然后蓝牙从机从响应通道反馈[0x00,0x81]。
 */
const sendPartitionCount = () => {};

/**
 * 发送分区信息
 * 第三步，解析 HEX16 文件，开始发送分区信息和分区数据，进行逐个分区的数据发送。
 * 分区的划分界限为以“:02”为行开头的行数至当下一个以“:02”为行开头的行数减一。
 */
const sendPartitionFrame = () => {};
